
#include "kernel/log/log.h"
#include "kernel/interrupt/interrupt.h"
#include "kernel/memory/memory.h"
#include "kernel/driver/keyboarddriver.h"
#include "kernel/driver/mousedriver.h"
#include "kernel/task/task.h"
#include "kernel/smp/smp.h"
#include "libs/lib.h"
#include "kernel/timer/time.h"
#include "kernel/driver/disk.h"
#include "kernel/apic/ipi.h"
#include "kernel/vfs/fat32.h"
#include "kernel/vfs/vfs.h"
#include "kernel/syscall/syscall.h"
#include "libs/string.h"
#include "libs/path.h"
#define APIC
#ifdef APIC
#include "kernel/apic/apic.h"
#else
#include "kernel/dirver/8259a.h"
#endif

extern char _data_init;
extern "C" void testDisk(void);
extern "C" void user_level_function(void);
extern "C" void ret_system_call(void);




void memoryTest(){



	Page* page;
	uint16_t i = 0;
	page = MEMORY->alloc_pages(ZONE_NORMAL,63, 0);
	page = MEMORY->alloc_pages(ZONE_NORMAL,63, 0);

	LOG_INFO("4.MEMORY->globalMemoryDesc.bits_map:%#018lx\tMEMORY->globalMemoryDesc.bits_map+1:%#018lx\tMEMORY->globalMemoryDesc.bits_map+2:%#018lx\tzone_struct->page_using_count:%d\tzone_struct->page_free_count:%d\n",*MEMORY->globalMemoryDesc.bits_map,*(MEMORY->globalMemoryDesc.bits_map+1),*(MEMORY->globalMemoryDesc.bits_map+2),MEMORY->globalMemoryDesc.zones_struct->page_using_count,MEMORY->globalMemoryDesc.zones_struct->page_free_count);

	// for(i = 80;i <= 85;i++)
	// {
	// 	LOG_INFO("page%03d attribute:%#018lx address:%#018lx\t",i,(MEMORY->globalMemoryDesc.pages_struct + i)->attribute,(MEMORY->globalMemoryDesc.pages_struct + i)->PHY_address);
	// 	i++;
	// 	LOG_INFO("page%03d attribute:%#018lx address:%#018lx\n",i,(MEMORY->globalMemoryDesc.pages_struct + i)->attribute,(MEMORY->globalMemoryDesc.pages_struct + i)->PHY_address);
	// }

	// for(i = 140;i <= 145;i++)
	// {
	// 	LOG_INFO("page%03d attribute:%#018lx address:%#018lx\t",i,(MEMORY->globalMemoryDesc.pages_struct + i)->attribute,(MEMORY->globalMemoryDesc.pages_struct + i)->PHY_address);
	// 	i++;
	// 	LOG_INFO("page%03d attribute:%#018lx address:%#018lx\n",i,(MEMORY->globalMemoryDesc.pages_struct + i)->attribute,(MEMORY->globalMemoryDesc.pages_struct + i)->PHY_address);
	// }

	// MEMORY->free_pages(page,1);
	
	// LOG_INFO("5.MEMORY->globalMemoryDesc.bits_map:%#018lx\tMEMORY->globalMemoryDesc.bits_map+1:%#018lx\tMEMORY->globalMemoryDesc.bits_map+2:%#018lx\tzone_struct->page_using_count:%d\tzone_struct->page_free_count:%d\n",*MEMORY->globalMemoryDesc.bits_map,*(MEMORY->globalMemoryDesc.bits_map+1),*(MEMORY->globalMemoryDesc.bits_map+2),MEMORY->globalMemoryDesc.zones_struct->page_using_count,MEMORY->globalMemoryDesc.zones_struct->page_free_count);

	// for(i = 75;i <= 85;i++)
	// {
	// 	LOG_INFO("page%03d attribute:%#018lx address:%#018lx\t",i,(MEMORY->globalMemoryDesc.pages_struct + i)->attribute,(MEMORY->globalMemoryDesc.pages_struct + i)->PHY_address);
	// 	i++;
	// 	LOG_INFO("page%03d attribute:%#018lx address:%#018lx\n",i,(MEMORY->globalMemoryDesc.pages_struct + i)->attribute,(MEMORY->globalMemoryDesc.pages_struct + i)->PHY_address);
	// }
	
	page = MEMORY->alloc_pages(ZONE_UNMAPED,63, 0);

	LOG_INFO("6.MEMORY->globalMemoryDesc.bits_map:%#018lx\tMEMORY->globalMemoryDesc.bits_map+1:%#018lx\tzone_struct->page_using_count:%d\tzone_struct->page_free_count:%d\n",*(MEMORY->globalMemoryDesc.bits_map + (page->PHY_address >> PAGE_2M_SHIFT >> 6)) , *(MEMORY->globalMemoryDesc.bits_map + 1 + (page->PHY_address >> PAGE_2M_SHIFT >> 6)),page->zone_struct->page_using_count,page->zone_struct->page_free_count );
	
	MEMORY->free_pages(page,1);

	LOG_INFO("7.MEMORY->globalMemoryDesc.bits_map:%#018lx\tMEMORY->globalMemoryDesc.bits_map+1:%#018lx\tzone_struct->page_using_count:%d\tzone_struct->page_free_count:%d\n",*(MEMORY->globalMemoryDesc.bits_map + (page->PHY_address >> PAGE_2M_SHIFT >> 6)) , *(MEMORY->globalMemoryDesc.bits_map + 1 + (page->PHY_address >> PAGE_2M_SHIFT >> 6)) ,page->zone_struct->page_using_count,page->zone_struct->page_free_count);


}




extern "C" void Start_Smp(void){

	
	APICMANAGER->initLocalApic();

	TASKMANAGER->initIdleTask();
	TASKMANAGER->initTaskSchedule();
	current->cpuId = getAPICID();

	uint64_t* stack = (uint64_t*)((uint64_t)MEMORY->kmalloc(STACK_SIZE,0) + STACK_SIZE);
	uint64_t* ptr = (uint64_t*)((uint64_t)MEMORY->kmalloc(STACK_SIZE,0) + STACK_SIZE);

	INTERRUPTMANAGER->InitTSS(10 + getAPICID() * 2,(uint64_t*)&init_tss[getAPICID()],(uint64_t)stack,(uint64_t)ptr);

	current->thread->rsp0 = (uint64_t)stack;
	current->thread->rsp = (uint64_t)stack - sizeof(StackFrame);

	SpinlockUnlock(&SMPMANAGER->smpSpinlock);


	sti();


	INTERRUPTMANAGER->taskManagerHaveFinish = 1;

	while(1){

		hlt();

	}

}


uint64_t init(unsigned long arg)
{




	StackFrame *regs;

	new Fat32FS();

	current->thread->rip = (unsigned long)ret_system_call;
	current->thread->rsp = (unsigned long)current + STACK_SIZE - sizeof(StackFrame);
	current->thread->gs = USER_DS;
	current->thread->fs = USER_DS;
	current->flags &= ~PF_KTHREAD;
	
	regs = (StackFrame*)(current->thread->rsp);
	LOG_INFO("init finish\n");
	__asm__	__volatile__	(	"movq	%1,	%%rsp	\n\t"
					"pushq	%2		\n\t"
					"jmp	do_execve	\n\t"
					::"D"(regs),"m"(current->thread->rsp),"m"(current->thread->rip),"S"("/init.bin")
					:"memory");
        
}




extern "C" void Start_Kernel(void)
{

	

	vbelog vbe;
	interruptmanager interrupts;
	SoftInterruptManager softInterm;

	memorymanage memorys;
	cpumanager cpum;
	// memoryTest();
	
#ifdef APIC
	ApicManager apicmanage;
	
#else
	pic8259aManager pic8259am;
#endif
	

	IpiManager ipima;
		// disktest();
	taskmanager taskm;
	TimeManager timemanager;

	systemcallmanager syscallm;
	SmpManager smpm;
	
	DiskManager diskmanager(&interrupts);
	
	// ApicTimer apc((uint64_t)0x20);
	// TimerTask* te = new TimerTask(5);
	// TIMEMANAGER->addTimerTask(te);
	// TimerTask* te = new TimerTask(3);
	// TIMEMANAGER->addTimerTask(te);
	// 
	VFS vfsmanager;

	keyboarddriver keyboard(&interrupts);
	// MouseDriver moused(&interrupts);

	TASKMANAGER->taskInit();


	
	

	while(1){
		

		// static int count2 = 0;

        // if(TIMEMANAGER->timeCount - count2 >= 1){
        //     count2 = TIMEMANAGER->timeCount;
		// 	LOG_INFO("idle thread\n");
        // }
	}

	// while(1){
	// 	if(keyboard.count)
	// 		keyboard.analysisKeycode();
	// 	if(moused.count)
	// 		moused.analysisMouseCode();
	// }
}
